package db;

import java.util.Collection;
import java.util.List;

import core.exceptions.DBAccessException;
import core.objects.ObjectWithID;

public interface IDBAccess<T extends ObjectWithID> {

	/**
	 * Checks whether an entry with given name exists for object in database
	 */
	public boolean exists(String name) throws DBAccessException;
	
	/**
	 * Checks whether an entry with given name of object obj exists for object
	 * in database. For example, calling exists("hello", 5, new Book(0, ""))
	 * on User, returns whether or not user 5 has the book "hello"
	 */
	public boolean exists(String name, int id, ObjectWithID obj) throws DBAccessException;
	
	/**
	 * Checks whether an entry with given name of object obj exists for object
	 * in database. For example, calling exists(4, 9, new Book(0, "")) on User
	 * returns whether user 9 has the book id 4.
	 */
	public boolean exists(int idToCheck, int id, ObjectWithID obj) throws DBAccessException;
	
	/**
	 * Performs select Query on the object based on the supplied id,
	 * (for example, return List<Book> for "SELECT * FROM book WHERE book_id = id")
	 *
	 */
	public List<T> select(int id) throws DBAccessException;

	/**
	 * Performs select Query on a cross table based on this object
	 * with the giving id. Second parameter obj specifies which
	 * cross object to select, for example for the call:
	 * 
	 * select(10, new Category(0, ""))
	 * 
	 * the method would run the query "SELECT book.* FROM book_cross_category, book, category
	 * WHERE ... AND category_id = 10" and a List<Book> would be returned.
	 * 
	 * For any object specified which doesn't hold a cross relation with
	 * this interface's generic T object, T would be selected and this
	 * method would be similar select(id) method
	 * 
	 * different implementations may vary from the above as needed.
	 *
	 */
	public List<T> select(int id, ObjectWithID obj) throws DBAccessException;
	
	/**
	 * Performs select Query on the object based on the supplied name,
	 * (for example, return List<Book> for "SELECT * FROM book WHERE book_name = name")
	 *
	 */
	public List<T> select(String name) throws DBAccessException;
		
	/**
	 * Performs select Query on a cross of the object based on the supplied name
	 * and object.
	 * 
	 * For example, for the call select("Rowling", new Author(0, ""))
	 * would return a List<Book> of books who come up in the query
	 * "SELECT book.* FROM book_cross_author, author, book WHERE ... AND author.name = "Rowling"
	 * 
	 * For any object specified which doesn't hold a cross relation
	 * with this interface's generic T object, T will be selected and
	 * this method would be similar to select(name) method
	 *
	 */
	public List<T> select(String name, ObjectWithID obj) throws DBAccessException;

	/**
	 * Performs select Query on the object based on the supplied name,
	 * (for example, return List<Book> for "SELECT * FROM book WHERE book_name like '%name%'")
	 *
	 */
	public List<T> selectContains(String name) throws DBAccessException;

	/**
	 * Performs select Query on the object based on the supplied name,
	 * (for example, return List<Book> for "SELECT * FROM book WHERE book_name like '%name%'")
	 *
	 * @param limitSearch limits the search results per Configurations attribute's value
	 */
	public List<T> selectContains(String name, boolean limitSearch) throws DBAccessException;

	/**
	 * Performs select Query on a cross of the object based on the supplied name
	 * and object.
	 * 
	 * For example, for the call select("Rowling", new Author(0, ""))
	 * would return a List<Book> of books who come up in the query
	 * "SELECT book.* FROM book_cross_author, author, book WHERE ... AND author.name like "%Rowling%"
	 * 
	 * For any object specified which doesn't hold a cross relation
	 * with this interface's generic T object, T will be selected and
	 * this method would be similar to select(name) method
	 *
	 */
	public List<T> selectContains(String name, ObjectWithID obj) throws DBAccessException;

	/**
	 * Performs select Query on a cross of the object based on the supplied name
	 * and object.
	 * 
	 * For example, for the call select("Rowling", new Author(0, ""))
	 * would return a List<Book> of books who come up in the query
	 * "SELECT book.* FROM book_cross_author, author, book WHERE ... AND author.name like "%Rowling%"
	 * 
	 * For any object specified which doesn't hold a cross relation
	 * with this interface's generic T object, T will be selected and
	 * this method would be similar to select(name) method
	 *
	 * @param limitSearch limits the search results per Configurations attribute's value
	 */
	public List<T> selectContains(String name, ObjectWithID obj, boolean limitSearch) throws DBAccessException;

	/**
	 * Returns average (rating) of object by id
	 */
	public float selectAvg(int id) throws DBAccessException;
	
	/**
	 * Returns num of elements by id. For instance, if operating on
	 * BookComment returns how many book comments a book_id has.
	 */
	public int selectCount(int id, ObjectWithID obj) throws DBAccessException;
	
	/**
	 * Returns a list of all elements within db table.
	 * 
	 * This method should only be used for Lookup Tables,
	 * and not for big-data tables (meaning, use this for
	 * City, Country, Publisher, Category, etc, but not
	 * for User, Book, Comment/Cross tables and so on).
	 */
	public List<T> selectAll() throws DBAccessException;
	
	/**
	 * Returns a list of all elements within db table related to cross.
	 * 
	 * selectAll(10, new Category(0, ""))
	 * 
	 * the method would run the query "SELECT category.* FROM book_cross_category, book, category
	 * WHERE ... AND book_id = 10" and a List<Category> would be returned.
	 * 
	 * For any object specified which doesn't hold a cross relation with
	 * this interface's generic T object, T would be selected and this
	 * method would be similar select(id) method
	 * 
	 */
	public List<? extends ObjectWithID> selectAll(int id, ObjectWithID obj) throws DBAccessException;
	
	/**
	 * inserts the object into the database.
	 *
	 */
	public void insert(T obj) throws DBAccessException;
	
	/**
	 * insert a CROSS object into the database.
	 * 
	 * For example, insert(book, category) inserts a new
	 * record to book_cross_category table, connecting
	 * between the two object ids.
	 * 
	 */
	public void insert(T obj, ObjectWithID base) throws DBAccessException;
	
	/**
	 * inserts a collection of objects into the database.
	 */
	public void insertAll(Collection<T> objs) throws DBAccessException;
	
	/**
	 * inserts a collection of CROSS objects into the database.
	 * 
	 * For example, insert(book, book.getCategories()) inserts
	 * all categories saved in book objects with the book_id
	 * of book to book_cross_category table.
	 */
	public void insertAll(T obj, Collection<? extends ObjectWithID> objs) throws DBAccessException;

	/**
	 * inserts a collection of filter objects to cross objects of objs.
	 * For example, if objs are a collection of books and filter is Category,
	 * insert all categories in book.getCategories() for each book
	 */
	public void insertAll(Collection<? extends ObjectWithID> objs, ObjectWithID filter) throws DBAccessException;	

	/**
	 * Updates the values of obj in database (does nothing if no object with
	 * obj.getID() exists in database)
	 */
	public void update(T obj) throws DBAccessException;
	
	/**
	 * Updates the values of all objects in database (does nothing for objects whose getID()
	 * doesn't exist in database)
]	 */
	public void update(Collection<T> objs) throws DBAccessException;
	
	/**
	 * deletes object from database
	 */
	public void delete(T obj) throws DBAccessException;

	/**
	 * delete connection between the objects in database.
	 * For example, calling on Book with delete(bookWithID5, categoryWithID10)
	 * deletes relation between book 5 and category 10.
	 */
	public void delete(T obj1, ObjectWithID obj2) throws DBAccessException;

	/**
	 * deletes all objects from database
	 */
	public void delete(Collection<T> objs) throws DBAccessException;

	/**
	 * delete connection between the objects in database.
	 * 
	 * For example, calling on Book with delete(bookWithID5, bookWithID5.getCategories())
	 * deletes relation between book 5 and all its' categories.
	 */
	public void delete(T obj, Collection<? extends ObjectWithID> objs) throws DBAccessException;
}
